/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package retrival;
import java.util.Arrays;
import java.util.ArrayList;
import java.io.*;

/**
 *
 * @author Administrator
 */
public class TPsOnSlidingWindow {
    public StockPrice[] prices;
    public int priceCount,CountP,TL,P;
    public int[] PointLevel1,TPLength,TPFinal,PIP;
    public double[] PAA;
    private double error_Paa;
    public int[] Patterns;
    public int[] TPFinal5,TPFinal1,TPFinal2,TPFinal3,TPFinal4;//,TPFinal80;
    public int[] PIP5,PIP1,PIP2,PIP3,PIP4,PIP80;
    public double[] PAA5,PAA10,PAA20,PAA40;

    public int[] TPPattern5,TPPattern10,TPPattern20,TPPattern40;
    public int[] PIPPattern5,PIPPattern10,PIPPattern20,PIPPattern40;
    public int[] PAAPattern5,PAAPattern10,PAAPattern20,PAAPattern40;
    
    TPsOnSlidingWindow (String stockid, String date1, String date2)
    {
        jdbcmysql db = new jdbcmysql();
        db.initial();
        prices = db.getStockPrice(stockid,date1,date2);
        priceCount = db.getPriceCount();
      //    ConfigurePriceExample2();

        // window size = 5,2,3,6,11; you can change to others
        PointLevel1 = getTP1(PointLevel1);
        TPFinal5 = High_Level_TPs1(5);
        TPFinal1= High_Level_TPs1(2);
        TPFinal2= High_Level_TPs1(3);
        TPFinal3= High_Level_TPs1(6);
        TPFinal4= High_Level_TPs1(11);

        PIP1= PIP(TPFinal1.length);
        PIP2= PIP(TPFinal2.length);
        PIP3= PIP(TPFinal3.length);
        PIP4= PIP(TPFinal4.length);
      
    }


     private void ConfigurePriceExample1()
   {
       prices = null;
       int a =0;
       prices = new StockPrice[16+a];
       prices[0]= new StockPrice("0",0.3);prices[1]=new StockPrice("1",2.2);prices[2+a]=new StockPrice("2",0.5);
      // prices[0]= new StockPrice("0",0.7);prices[1]=new StockPrice("1",1.5);prices[2+a]=new StockPrice("2",1);
       prices[3+a]= new StockPrice("0",1.6);prices[4+a]=new StockPrice("1",1.3);prices[5+a]=new StockPrice("2",2.6);
       prices[6+a]= new StockPrice("0",1.7);prices[7+a]=new StockPrice("1",1.9);
        prices[8+a]=new StockPrice("2",1.2);
       prices[9+a]=new StockPrice("2",2.2); prices[10+a]=new StockPrice("2",1.6); prices[11+a]=new StockPrice("2",2.3);
        prices[12+a]=new StockPrice("2",1.9); prices[13+a]=new StockPrice("2",2.2); prices[14+a]=new StockPrice("2",1.8);
       prices[15+a]=new StockPrice("2",1.7);

       priceCount = 16+a;
       for(int i =0;i< 16;i++)
           PointLevel1[i] = i;
   }

      private void ConfigurePriceExample2()
   {
       prices = null;
       prices = new StockPrice[12];
       prices[0]= new StockPrice("0",1.5);prices[1]=new StockPrice("1",3);prices[2]=new StockPrice("1",2.5);prices[3]=new StockPrice("2",4);
       prices[4]= new StockPrice("0",3.4);prices[5]=new StockPrice("1",3.1);prices[6]=new StockPrice("2",3.7);
       prices[7]= new StockPrice("0",4.2);prices[8]=new StockPrice("1",3.8);prices[9]=new StockPrice("2",4.1);
       prices[10]=new StockPrice("2",3); prices[11]=new StockPrice("2",2.7);
       priceCount = 12;
       PointLevel1 = new int[12];
       for(int i =0;i< 12;i++)
           PointLevel1[i] = i;
   }

    private void print  (String s, double[] error)
    {
      try
      {
       FileWriter fileWriter=new FileWriter(s);
       for (int i = 0; i < error.length; i++) {
        fileWriter.write(String.valueOf(error[i])+"\r\n");
         }
       fileWriter.flush();
       fileWriter.close();
       }catch (Exception e) {
             e.printStackTrace();
       }
    }

    private int[] cout (int[] p)
    {
       int count1 =0,count2=0 ;
       for(int i =1; i<p.length-1;i++)
      {
          if(prices[p[i]].Price<prices[p[i-1]].Price&&prices[p[i]].Price<prices[p[i+1]].Price)
              count1++;
          if(prices[p[i]].Price>prices[p[i-1]].Price&&prices[p[i]].Price>prices[p[i+1]].Price)
              count2++;
      }
       int[] count = new int[2];
       count[0] = count1; count[1] = count2;
       return count;
   }

    int[] PIPsorting(int[] PIP)
    {
        int[] PIPnew = new int[PIP.length];
       for(int i =0;i<PIP.length;i++)
       {
           int k=0;
           for(;k<i&&PIPnew[k]<PIP[i];k++)
               ;
           if(k==i)
               PIPnew[k] = PIP[i];
           else
           {
               for(int j = i;j>k;j--)
                   PIPnew[j] = PIPnew[j-1];
               PIPnew[k] = PIP[i];
           }
       }
        return PIPnew;
    }

    public int[] getTP1(int [] PointLevel1)
    {

       int CountTP=0;
       int[] storeIndex = new int[priceCount];

       storeIndex[CountTP]= 0;
       int i =1;
       for(;i<priceCount-1;i++)
       {
                storeIndex[++CountTP]=i;
       }

       storeIndex[++CountTP]=priceCount-1;

       PointLevel1= new int[CountTP+1];
       for(int k=0; k<= CountTP;k++)
           PointLevel1[k]= storeIndex[k];

       return PointLevel1;
   }
   
    private double[] PAA(int L)
    {    
        TL = priceCount/L; error_Paa =0;
        int i = 1,sum=0,indexCount = 0;
        if(priceCount%TL!=0)
            PAA = new double[1+priceCount/TL];
        else
            PAA = new double[priceCount/TL];

        for(;i<priceCount+1;i++)
        {
            if(i%TL==0)
            {
                PAA[indexCount++] = (double)(sum / TL);
                for(int k =i-TL;k<i;k++)
                {
                    error_Paa += Math.abs(PAA[indexCount-1]-prices[k].Price);
                }
                sum = 0;
            }
            else
                sum+=prices[i-1].Price;
        }
       if(priceCount%TL!=0)
       {
           PAA[indexCount] =(double) sum/((priceCount%TL)+1);
            for(int k =priceCount%TL;k>0;k--)
             error_Paa += Math.abs(PAA[indexCount]-prices[priceCount-k].Price);
        }
        error_Paa=(int)( error_Paa/4000);
        return PAA;
    }

    public int[] PIP(int L)
    {
       PIP = new int [L];
       ArrayList points =new ArrayList();
       points.add(0);
       points.add(priceCount-1);
       
       int indexCount = 0;
       PIP[indexCount++] = 0;
       PIP[indexCount++] = priceCount-1;
       double error = 0;
       for(int i = L-2;i>0;i--)
       {
           error = 0;
           int index =0 ;
           for(int j=0;j<points.size()-1;j++)
           {
               int t1 = Integer.parseInt (points.get(j).toString());
               int t2 = Integer.parseInt (points.get(j+1).toString());
               double p1=prices[t1].Price,p2=prices[t2].Price;
               double e = ErrorPiP(t1,t2);
               
               if(e>error)
               {
                   error = e;
                   PIP[indexCount]=P;
               }
            }
       int j = 0;
       for(;Integer.parseInt (points.get(j).toString())<PIP[indexCount];j++)
          ;
       points.add(j,PIP[indexCount]);

       indexCount++;

     }
       return PIPsorting(PIP);
   }

    private double PAAError()
    {
        double error = 0;
        for(int i =0;i<PAA.length;i++)
        {
            int indexbase = i* TL;
            for(int j = 0;j<TL&&(indexbase+j<priceCount);j++)
            {
                error+= Math.abs(prices[indexbase+j].Price - PAA[i]);
            }
        }
        return error/4000;
    }

    private double ErrorPiP(int i, int j) // max distance
    {
       double error = 0;
       double p1= prices[i].Price,p2=prices[j].Price;
       double n=( p2-p1)/ (j-i);
       int k = i+1;
        for(;k<=j;k++)
        {
           double p3=prices[k].Price;
           double e = Math.abs(p1 + n *(k-i) - p3);
           if (e>error)
           {
               error = e;
               P=k;
            }
        }
       
       return error;
   }

    public void print  (String s, int[] error)
    {
      try
      {
       FileWriter fileWriter=new FileWriter(s);
       for (int i = 0; i < error.length; i++) {
        fileWriter.write(String.valueOf(error[i])+"\r\n");
         }
       fileWriter.flush();
       fileWriter.close();
       }catch (Exception e) {
             e.printStackTrace();
       }
    }

    void High_Level_TPs(int length)
    {
        int PHL_index = 0;
        int start = PointLevel1[0];
        int max=start, min = start;

        int[] PointHighLevel = new int[PointLevel1.length];
        
        PointHighLevel[PHL_index] = PointLevel1[0];

        for(int i =1;i<PointLevel1.length;i++)
        {
           if(PointLevel1[i]-start < length)
           {
               double p = prices[PointLevel1[i]].Price;
               if(prices[max].Price < p )
                   max = PointLevel1[i];
               if(prices[min].Price > p)
                   min = PointLevel1[i];
            }
           if(PointLevel1[i]-start >= length||i == PointLevel1.length-1)
           {  
             if(max<min)
                 {
                       {
                            PointHighLevel[++PHL_index]= max;
                            PointHighLevel[++PHL_index]= min;
                           
                       }
               }
               else if (max>min)
               {
                       {
                            PointHighLevel[++PHL_index]= min;
                            PointHighLevel[++PHL_index]= max;
                       }
               }
              else
               {
                   PointHighLevel[++PHL_index]= min; 
                }    
               start = PointLevel1[i];
               max = start;
               min = start;
            }
        }

        PointHighLevel[++PHL_index]= PointLevel1[PointLevel1.length-1];

        int [] TPLength1 = new int[PHL_index+1];
        int CountTP = 0;
        TPLength1[0] = TPLength1[0];

        for(int i =1; i < TPLength1.length;i++)
       {
            TPLength1[++CountTP]=PointHighLevel[i];
       }
        TPLength = new int [CountTP+1];
        for(int i=0;i<TPLength.length;i++)
            TPLength[i] = TPLength1[i];
        
       int [] TPF = new int[TPLength.length];
       int Count = 0;
       TPF[0] = TPLength[0];

       int i =1;
       for(; i < TPLength.length;)
       {
           if(i < TPLength.length-3)
           {
             double [] p = new double[3];
             p[0]= prices[TPLength[i]].Price; //p[3]= prices[TPLength[i+3]].Price;
             p[1]= prices[TPLength[i+1]].Price; p[2]=prices[TPLength[i+2]].Price;

           
             if(TPLength[i+1]-TPLength[i+0] < length)
             {
                 if((p[0]<p[1]&&p[0]<p[2])||(p[0]>p[1]&&p[0]>p[2]))
                 {
                     TPF[++Count] = TPLength[i++];
                 }
                 else
                     i++;
              }
              else
               TPF[++Count] = TPLength[i++];
           }
           else
               TPF[++Count] = TPLength[i++];
       }

        int CountA = 0;
        int [] TPFi = new int [Count+1];
        TPFi[0] = TPF[0];
       for(int k =1;k<TPF.length-1;k++)
       {
           if(((prices[TPF[k]].Price<prices[TPF[k-1]].Price&&prices[TPF[k]].Price<prices[TPF[k+1]].Price)
              ||(prices[TPF[k]].Price>prices[TPF[k-1]].Price&&prices[TPF[k]].Price>prices[TPF[k+1]].Price)))
               TPFi[++CountA] = TPF[k];
       }

       TPFinal = new int[CountA+1];
       for(int j =0; j< CountA+1;j++)
           TPFinal[j] = TPFi[j];
    }

    int[] High_Level_TPs1(int length)
    {
        int PHL_index = -1;
        int start = 0;
        int max=0, min = 0;

        int[] PointHighLevel = new int[PointLevel1.length*2];

        for(int i =1;i<PointLevel1.length;i++)
        {
           if(PointLevel1[i]-PointLevel1[start] < length)
           {
               double p = prices[PointLevel1[i]].Price;
               if(prices[PointLevel1[max]].Price < p )
                   max = i;
               if(prices[PointLevel1[min]].Price > p)
                   min = i;
            }
           if(PointLevel1[i]-PointLevel1[start] >= length)
           {
             if(max<min)
                 {
                       {
                            PointHighLevel[++PHL_index]= PointLevel1[max];
                            PointHighLevel[++PHL_index]= PointLevel1[min];
                            max = min;
                            start = min;
                            i = min;
                       }
               }
               else if (max>min)
               {
                       {
                            PointHighLevel[++PHL_index]= PointLevel1[min];
                            PointHighLevel[++PHL_index]= PointLevel1[max];
                            min = max;
                            start = max;
                            i = max;
                       }
               }
              else
               {
                   PointHighLevel[++PHL_index]= PointLevel1[min];
                   start = i+1;
                   max = start;
                   min = start;
                }

            }
         else if (i == PointLevel1.length-1)
         {
              if(max<min)
                 {
                       {
                            PointHighLevel[++PHL_index]= PointLevel1[max];
                            PointHighLevel[++PHL_index]= PointLevel1[min];
                       }
               }
               else
               {
                       {
                            PointHighLevel[++PHL_index]= PointLevel1[min];
                            PointHighLevel[++PHL_index]=PointLevel1[max];
                       }
               }
         }
          else
               ;
        }

       int PLL = PointHighLevel.length-1,C=1;
       for(int x =1;x<PLL;)
       {
           double p0 = prices[PointHighLevel[x-1]].Price, p1 = prices[PointHighLevel[x]].Price,p2=prices[PointHighLevel[x+1]].Price;
           if(PointHighLevel[x+1]!=0&&((p1>p0&&p1>p2)||(p1<p0&&p1<p2)))
           {
              x++;
              C++;
           }
           else
           {
               for(int k = x;k<PointHighLevel.length-1&&PointHighLevel[x+1]!=0;k++)
                   PointHighLevel[k] = PointHighLevel[k+1];
               PLL--;
          }
        }
        
       ArrayList points =new ArrayList();

       for(int j =0; j< C+1;j++)
           points.add( PointHighLevel[j]);

       int [] TPF1 = new int[C+2];

       int i =1, Count=-1;
       TPF1[++Count] = PointHighLevel[0];

       // additional step 1
       for(; points.size()-3>0;)
       {
             int p1 = Integer.parseInt (points.get(0).toString()),p2=Integer.parseInt (points.get(1).toString()),p3=Integer.parseInt (points.get(2).toString());
             double [] p = new double[3];
             double a = 0.45,b=0.95;
             p[0]= prices[p1].Price; //p[3]= prices[TPLength[i+3]].Price;
             p[1]= prices[p2].Price; p[2]=prices[p3].Price;

             if(p3-p1 < b*length)
             {
                 if(!((p[2] < p[0] && p[2] < p[1]) || (p[2] > p[0] && p[2] > p[1])))
                 {
                     points.remove(2);
                 }
                 else if(!((p[0]<p[1]&&p[0]<p[2])||(p[0]>p[1]&&p[0]>p[2])))
                 {
                     points.remove(0);
                 }
                 else
                 {
                      points.remove(1);
                 }  
              }
             else if (p2-p1< a*length)
             {
                if(!((p[1] < p[0] && p[1] < p[2]) || (p[1] > p[0] && p[1] > p[2])))
                 {
                     points.remove(1);
                 }
                else  if(!((p[0]<p[1]&&p[0]<p[2])||(p[0]>p[1]&&p[0]>p[2])))
                 {
                     points.remove(0);
                 }
                 else
                {
                    TPF1[++Count] = p1;points.remove(0);
                 }
             }
              else if (p3-p2 < a*length)
             {
                 if(!((p[2]<p[1]&&p[2]<p[0])||(p[2]>p[1]&&p[2]>p[0])))
                 {
                     points.remove(2);
                 }
                else if(!((p[1] < p[0] && p[1] < p[2]) || (p[1] > p[0] && p[1] > p[2])))
                 {
                     points.remove(1);
                 }
                 else
                 {TPF1[++Count] = p1;points.remove(0);}
             }
              else
             {
               TPF1[++Count] = p1;points.remove(0);
           }
       }

       for(int k =0;k<points.size();k++)
       {
           TPF1[++Count]=Integer.parseInt (points.get(k).toString());
       }
      int[] TPFtemp = new int[Count+1];

      // additional step 2
      int k =1,CountTemp=0;
      TPFtemp[CountTemp] = TPF1[0];
      for(;k<Count;k++)
      {
          double factor = 1;
          if((prices[TPF1[k]].Price>factor*prices[TPF1[k-1]].Price&&prices[TPF1[k]].Price>factor*prices[TPF1[k+1]].Price)||(factor*prices[TPF1[k]].Price<prices[TPF1[k-1]].Price&&factor*prices[TPF1[k]].Price<prices[TPF1[k+1]].Price))
              TPFtemp[++CountTemp] = TPF1[k];
      }
      TPFtemp[++CountTemp] = TPF1[Count];

      TPFinal = new int[CountTemp+1];
       for(int j =0; j< CountTemp+1;j++)
       {
         TPFinal[j] = TPFtemp[j];
        }
      return TPFinal;
    }

    int[] Get_pattern(int[] TP)
    {
       Patterns = new int [TP.length*7];
       CountP = 0;
       for(int i =0;i <TP.length-7;)
       {
           int TPs[] = new int[7];
           for(int j=0;j<7;j++)
               TPs[j] = TP[i+j];
           if(Head_shoulder(TPs))
           {
               for(int j=0;j<7;j++)
                 Patterns [CountP++] = TPs[j];
               i+=1;
           }
          else
              i++;
         }
       int[] P = new int[CountP];
       for(int i = 0;i<P.length;i++)
           P[i] = Patterns[i];
       return P;
    }

    boolean yes_Head_shoulder( double P[])
    {
        if( P[3]>P[2] && P[3]>P[6] &&
           P[1] > P[0] && P[1]>P[2] &&
           P[5]>P[4]&&P[5]>P[6]&&
           P[2]>P[0]&&
           P[4]>P[6]&&
           Math.abs(P[1]-P[5])<0.15*(P[1]+P[5]-P[2]-P[4])&&
           Math.abs(P[3]-P[4])<0.15*(P[1]+P[5]-P[2]-P[4]))
            return true;
        else if (
           P[3]<P[2] && P[3]<P[6] &&
           P[1] < P[0] && P[1]<P[2] &&
           P[5]<P[4]&&P[5]<P[6]&&
           P[2]<P[0]&&
           P[4]<P[6]&&
           Math.abs(P[1]-P[5])<-0.15*(P[1]+P[5]-P[2]-P[4])&&
           Math.abs(P[3]-P[4])<-0.15*(P[1]+P[5]-P[2]-P[4]))
            return true;
        else
            return false;
    }
     boolean  Head_shoulder(int TP_P[])
    {
        double[] P = new double [TP_P.length];
        for(int i =0;i<P.length;i++)
            P[i] = prices[TP_P[i]].Price;

      /*  if (yes_Head_shoulder(P))
            return true;
        else
            return false;*/
        if(P[3]> P[1] && P[3] > P[5] && P[3]>P[4]&&P[3]>P[2]&&
             P[1]> P[0]&&
             P[5]>P[6]&&
             P[2]>P[0]&&P[4]>P[6]
             &&P[3]-P[4]>Math.abs(P[5]-P[4])
             &&P[3]-P[2]>Math.abs(P[2]-P[1])
             &&P[0]<P[5]&&P[4]>P[0]&&P[1]>P[6]&&P[2]>P[6]
             )
        {return true;}
       else
                if ( P[3]< P[1] && P[3] < P[5] && P[3]<P[4]&&P[3]<P[2]&&
                  P[1]< P[0]&&
                  P[5]<P[6]&&
                  P[2]<P[0]&&P[4]<P[6]
                  &&P[3]-P[4]>Math.abs(P[5]-P[4])
                  &&P[2]-P[3]>Math.abs(P[2]-P[1])
                  && P[0]>P[5]&&P[4]<P[0]&&P[1]<P[6]&&P[2]<P[6]
                  )
        {return true;}
        else
            return false;
    }

    public int [] finding_patterns(int patternID)
    {

        int [] pat = new int [priceCount];
        int m = PointLevel1.length, n =7;

       int[][][] pattable = new int[m][n][n+1];

       for(int j = 0; j < n;j++)
       {
           pattable[0][j][0] = 1;
           pattable[0][j][1] = PointLevel1[0];
        }
       for(int i = 0; i<m;i++)
       {
           pattable[i][0][0] = 1;
           pattable[i][0][1] = PointLevel1[i];
        }

     //  System.out.print("x = "+ pattable[0][n-1][0]+"\n");

       int k = 0,patIndex = 0;
       for(int i = 1; i< m;i++)
       {
           for(int j = 1;j<n;j++)
           {
     
               for(;k<i && pattable[k][j-1][0]==j;k++)
               {
                   int[] matched_points = new int [pattable[k][j-1][0]+1];
                   for(int u =0;i<matched_points.length-1;u++)
                       matched_points[u] = pattable[k][j-1][u+1];
                   
                   matched_points[matched_points.length-1] = PointLevel1[i];
      
                   if (check_rules(matched_points,patternID)==true)
                   {
                       pattable[i][j][0]=pattable[k][j-1][0]+1;

                      // System.out.print("x = "+ pattable[i][j][0]+":"+ matched_points[0]+""+matched_points[1]+"\n");
                       
                       for(int v =0; v< matched_points.length;v++)
                            pattable[i][j][v+1]=matched_points[v];

                      if(j==n-1)
                       System.out.print("x = "+ pattable[i][j][0]+"\n");
                      
                    }
               }
           
           if(j==n-1 && pattable[i][n-1][0]== n-3)
           {
               System.out.print("ok");
               k = i;
               for(int x = 0; x < n;x++)
              {
                 pattable[i++][x][0] = 1;
                 pattable[i][x][1] = 0;
               }
               for(int u = 0; u<n;u++)
                   pat[patIndex++] = pattable[i][n-1][u+1];
           }

            }


           }
       for(int i = 0;i< pat.length;i++)
       {
           if(i%7==0)
               System.out.print( "\n");
           else
               System.out.print( pat[i] +"---"+prices[pat[i]].Price);
        }

        return pat;
    }

    boolean check_rules(int[] matched_points,int patternID)
       {
           int j = matched_points.length-1;
           boolean Yes = false;
           int[] p = new int [matched_points.length+1];
           p[0] =0;
           for(int i =0;i<matched_points.length;i++)
               p[i+1] = matched_points[i];

           if(j ==1 && p[1]  < p[2])
             return true;

           if(j ==2 && p[3]<p[2] && p[3]>p[1] && Math.abs(p[2]  - p[3])< Math.abs(p[3]-p[1]))
               return true;

           if(j ==3 && p[4]  > p[2])
             return true;

           if(j ==4 && p[5]  < p[4])
             return true;

           if(j ==5 && p[6]  < p[4] && Math.abs(p[6]-p[5])<Math.abs(p[4]-p[3]))
             return true;

            if(j ==6 && p[6]  > p[7])
             return true;
           
           return Yes;
       }

}
